Midterm 1

Author

Paul C

Published

October 4, 2025

Problema de Regresión

Caso de estudio, instituciones educativas y numero de estudiantes

Importamos CSV

Code
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

# Cargar datos
df = pd.read_csv('estudios.csv', sep=';', quotechar='"', encoding='utf-8', engine='python')

# Preprocesamiento
df['Anio'] = df['Anio_lectivo'].str.extract(r'(\d{4})').astype(int)
df = pd.get_dummies(df, columns=['Sostenimiento', 'Area', 'Regimen_Escolar'])
Code
df.head()
list(df.columns)
df.drop(columns=['Anio_lectivo', 'Zona','Nombre_Institucion'], inplace=True)
#list(df.columns)
Code
df.head()
list(df.columns)
['Provincia',
 'Cod_Provincia',
 'Canton',
 'Cod_Canton',
 'Parroquia',
 'Cod_Parroquia',
 'AMIE',
 'Tipo_Educacion',
 'Jurisdiccion',
 'Docentes_Femenino',
 'Docentes_Masculino',
 'Total_Docentes',
 'Estudiantes_Femenino',
 'Estudiantes_Masculino',
 'Total_Estudiantes',
 'Ecuatoriana',
 'Colombiana',
 'Venezolana',
 'Peruana',
 'Otros_Paises_de_America',
 'Otros_Continentes',
 'Anio',
 'Sostenimiento_Fiscal',
 'Sostenimiento_Fiscomisional',
 'Sostenimiento_Municipal',
 'Sostenimiento_Particular',
 'Area_Rural',
 'Area_Urbana',
 'Regimen_Escolar_Costa',
 'Regimen_Escolar_Sierra']

EDA

Simplemente se arreglaran datos, eliminacion de datos faltantes
Code
X = df[['Anio', 'Total_Docentes', 'Sostenimiento_Fiscal', 'Area_Rural']]  # por ejemplo
y = df['Total_Estudiantes']

# Modelo

Split, Pipeline y fit

Usaremos el train split para dividir el conjunto de datos 
 luego crearemos el pipeline con el escalado y la funcion de Regresion lineal, y luego usaremos fit del pipeline con los datos separados
Code
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_absolute_error
import altair as alt
from sklearn.metrics import mean_squared_error, r2_score

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)


pipe = Pipeline([
    ("escalado", StandardScaler()),
    ("lineal", LinearRegression())
])


# 7. Entrenar
pipe.fit(X_train, y_train)

# 8. Predecir
y_pred_pipe = pipe.predict(X_test)

### Evaluacion Probaremos este modelo con estas 3 valores de evaluacion

Code
rmse = mean_squared_error(y_test, y_pred_pipe)**0.5
r2 = r2_score(y_test, y_pred_pipe)

print("RMSE:", rmse)
mae = mean_absolute_error(y_test, y_pred_pipe)
print("Mae:", mae)
print("R²:", r2)
RMSE: 169.49257558489097
Mae: 73.31884183792116
R²: 0.8184550851844328

Graficos

Aqui realizaremos algunos graficos de este modelo para poder aprenciar el trabajo, y como esta funcionando el modelo a comparacion de la realidad

Code
import numpy as np

alt.data_transformers.disable_max_rows()


# Preparar datos de predicción
df_vp = pd.DataFrame({
    'Valores_Reales': y_test,
    'Predicciones': y_pred_pipe
})

# Leer datos de estudiantes
df_estudiantes = pd.read_csv('estudios.csv', sep=';')

# Agrupar estudiantes por provincia
df_provincias = df_estudiantes.groupby('Provincia').agg({
    'Total_Estudiantes': 'sum'
}).reset_index().sort_values('Total_Estudiantes', ascending=False)

# Crear selector para zoom/interacción
zoom = alt.selection_interval(bind='scales')

# 1. Gráfico scatter con línea de referencia
min_val, max_val = df_vp['Valores_Reales'].min(), df_vp['Valores_Reales'].max()

scatter = alt.Chart(df_vp).mark_circle(size=60, opacity=0.6).encode(
    x=alt.X('Valores_Reales', scale=alt.Scale(domain=[min_val, max_val])),
    y=alt.Y('Predicciones', scale=alt.Scale(domain=[min_val, max_val])),
    tooltip=['Valores_Reales', 'Predicciones']
).add_selection(zoom)

line = alt.Chart(pd.DataFrame({'x': [min_val, max_val]})).mark_line(
    color='red', strokeDash=[5, 5]
).encode(x='x', y='x')

scatter_plot = (scatter + line).properties(
    width=600,
    height=400,
    title='Predicciones vs Valores Reales'
)

# 2. Distribución de estudiantes por provincia
grafico_provincias = alt.Chart(df_provincias).mark_bar().encode(
    x=alt.X('Total_Estudiantes:Q', title='Número de Estudiantes'),
    y=alt.Y('Provincia:N', sort='-x', title='Provincia'),
    color=alt.Color('Total_Estudiantes:Q', scale=alt.Scale(scheme='blues')),
    tooltip=['Provincia', 'Total_Estudiantes']
).properties(
    width=600,
    height=400,
    title='Distribución de Estudiantes por Provincia'
).add_selection(zoom)

# 3. Métricas de rendimiento (alternativa ligera a curva de aprendizaje)
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error

metricas = {
    'Métrica': ['RMSE', 'MAE', 'R²'],
    'Valor': [
        np.sqrt(mean_squared_error(y_test, y_pred_pipe)),
        mean_absolute_error(y_test, y_pred_pipe),
        r2_score(y_test, y_pred_pipe)
    ]
}

df_metricas = pd.DataFrame(metricas)

grafico_metricas = alt.Chart(df_metricas).mark_bar().encode(
    x=alt.X('Valor:Q', title='Valor'),
    y=alt.Y('Métrica:N', title=''),
    color=alt.Color('Métrica:N', legend=None),
    tooltip=['Métrica', alt.Tooltip('Valor:Q', format='.4f')]
).properties(
    width=600,
    height=200,
    title='Métricas de Rendimiento del Modelo'
)

# Mostrar todos los gráficos
(scatter_plot & grafico_provincias & grafico_metricas)
C:\Users\pcstu\AppData\Local\Temp\ipykernel_11904\1896390425.py:13: DtypeWarning: Columns (21,22,23,24,25,26) have mixed types. Specify dtype option on import or set low_memory=False.
  df_estudiantes = pd.read_csv('estudios.csv', sep=';')
C:\Users\pcstu\AppData\Local\Temp\ipykernel_11904\1896390425.py:30: AltairDeprecationWarning: 
Deprecated since `altair=5.0.0`. Use add_params instead.
  ).add_selection(zoom)
C:\Users\pcstu\AppData\Local\Temp\ipykernel_11904\1896390425.py:52: AltairDeprecationWarning: 
Deprecated since `altair=5.0.0`. Use add_params instead.
  ).add_selection(zoom)
Code
grafico_provincias
Code
scatter_plot
Code
from sklearn.model_selection import learning_curve
import matplotlib.pyplot as plt
import numpy as np

train_sizes, train_scores, val_scores = learning_curve(
    estimator=pipe,
    X=X_train,
    y=y_train,
    cv=2,  # Solo 2 folds
    train_sizes=[0.5, 0.75, 1.0],  # Solo 3 puntos
    scoring='neg_mean_squared_error',
    n_jobs=1
)

train_scores_mean = np.sqrt(-train_scores.mean(axis=1))
val_scores_mean = np.sqrt(-val_scores.mean(axis=1))

df_learning = pd.DataFrame({
    'train_size': np.tile(train_sizes, 2),
    'score': np.concatenate([train_scores_mean, val_scores_mean]),
    'tipo': ['Entrenamiento']*len(train_sizes) + ['Validación']*len(train_sizes)
})

zoom = alt.selection_interval(bind='scales')

curva_aprendizaje = alt.Chart(df_learning).mark_line(point=True).encode(
    x='train_size:Q',
    y='score:Q',
    color='tipo:N',
    tooltip=['train_size', 'score', 'tipo']
).properties(
    width=600,
    height=400,
    title='Curva de Aprendizaje'
).add_selection(zoom)

curva_aprendizaje
C:\Users\pcstu\AppData\Local\Temp\ipykernel_11904\2307855108.py:35: AltairDeprecationWarning: 
Deprecated since `altair=5.0.0`. Use add_params instead.
  ).add_selection(zoom)

Resultados

El modelo explica bien la varianza de los datos, Los datos de RMSE indican valores bajos entre las predicciones y valores reales, lo que se puede apreciar los graficos especialmente en el scatter plot

Yachay Tech